package au.edu.qut.bpm.genbinder.genetic.other;

import java.io.File;
import java.io.FileOutputStream;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.deckfour.xes.in.XParser;
import org.deckfour.xes.in.XesXmlParser;
import org.deckfour.xes.model.XLog;
import org.deckfour.xes.out.XSerializer;
import org.deckfour.xes.out.XesXmlSerializer;

import au.edu.qut.bpm.genbinder.GeneticBinder;
import au.edu.qut.bpm.genbinder.models.Activity;
import au.edu.qut.bpm.genbinder.models.Case;
import au.edu.qut.bpm.genbinder.models.ConcreteEventLog;
import au.edu.qut.bpm.genbinder.models.Resource;
import au.edu.qut.bpm.genbinder.ui.CaseListPanel;
import au.edu.qut.bpm.genbinder.util.LogToXESConverter;
import au.edu.qut.bpm.genbinder.util.XESToLogConverter;

public class CopyOfLogRepairerSingleLog {
	//List<Activity> listActivity = new ArrayList<Activity>();
	//ConcreteEventLog log = null;
	//ConcreteEventLog log;
	//Map<Activity, Long> BST = new HashMap<Activity, Long>();

		public ConcreteEventLog RepairOneLog (ConcreteEventLog log) {
		//ConcreteEventLog newLog = log.clone();
		
		//ConcreteEventLog newLog = new ConcreteEventLog(log.getAbstractLog());
		
		//BST = log.getBoundStartTime();
		///*
		//for (Entry<Activity, Long> c : bST.entrySet()) {
		//	System.out.println(c.getKey() + " = " + c.getValue());
		//}
		///*
		int minute = 1000 * 60;
		XLog xesLog = LogToXESConverter.createLog(log, CaseListPanel.ZEROBLOCK, GeneticBinder.BLOCK_DURATION / minute);
		XSerializer serializer = new XesXmlSerializer();
		File file = new File("logs/repairexport.xes");
		
		try {
			FileOutputStream fos = new FileOutputStream(file, false);
			serializer.serialize(xesLog, fos);
			fos.flush();
			fos.close();
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		
		ConcreteEventLog newLog = null;
		
		XParser parser = new XesXmlParser();
		List<XLog> l;
		try {
			l = parser.parse(new File("logs/repairexport.xes"));
			
			XLog xlog = l.get(0);
			//ConcreteEventLog nLog = XESToLogConverter.createLog(xlog);
			newLog = XESToLogConverter.createLog(xlog);
			//newLog = new ConcreteEventLog(nLog.getAbstractLog());
			//newLog.setBoundStartTime(bST);
			
			//System.out.println("getAL-" + newLog.getAbstractLog().getActivities());
			//newLog.setAbstractLog(newLog.getAbstractLog());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		

		file.delete();
		//*/
		//long zeroBlock = DiscreteLogConverter.timeToLowerBlock(log.getLogArrival(), 0, GeneticBinder.BLOCK_DURATION) * GeneticBinder.BLOCK_DURATION;
		
		//log = DiscreteLogConverter.makeDiscrete(log, zeroBlock, GeneticBinder.BLOCK_DURATION);

		//CaseListPanel.TIMETOPIXELS = 30;		//block width per minute
		//CaseListPanel.ZEROBLOCK = zeroBlock;
		//this.log = log;
		//
		//int repairCount = 0;
		
		//while (!(newLog.isLogSafe() || newLog.isLogValid())) {
			/*
			System.out.println("repair-" + newLog.isLogSafe() + newLog.isLogValid() + "-" +
					newLog.getLogViolatingActivities().get(0).size()+newLog.getLogViolatingActivities().get(1).size()+
					newLog.getLogViolatingActivities().get(2).size()+newLog.getLogViolatingActivities().get(3).size());
			*/
			//System.out.println("repair" + log.getAbstractLog().getActivities());
			LinkedList<Activity> listOfAllActs = new LinkedList<Activity>(newLog.getAllActivity());
			listOfAllActs = newLog.getSortedActivity(listOfAllActs);
			
			Map<Case, LinkedList<Activity>> hmapCaseActs = new LinkedHashMap<Case, LinkedList<Activity>>();

			for (Case c : newLog.getAbstractLog().getCases()) {
				List<Activity> fixedActPrecedence = c.getOrderedTrace();
				LinkedList<Activity> listActPerCase = new LinkedList<Activity>();
				
				for (Activity a : fixedActPrecedence) {
					listActPerCase.add(a);
				}
				listActPerCase = newLog.getFixedTraceOrderAndOverlap(listActPerCase);
				hmapCaseActs.put(c, listActPerCase);
			}
			for (Activity a : listOfAllActs) {
				long activityStartTime = newLog.getActivityStart(a);
				long activityEndTime = newLog.getActivityEnd(a);
				Set<Resource> res = new HashSet<Resource>(a.getResource());
				//System.out.println("starttime==" + activityStartTime);
				LinkedList<Activity> listClashingActs = new LinkedList<Activity>(newLog.getClashingActivitiesWithin(a, activityStartTime, activityEndTime, res));
				//System.out.println("repair2-" + listClashingActs.size() + "-" + z++);
				for (Activity a2 : newLog.getSortedActivities(listClashingActs)) {
					long originalStartTime = newLog.getActivityStart(a2);
					long newStartTime = activityEndTime;
					long timeDifference = newStartTime - originalStartTime;
					Case activityCase = a2.getCase();
					Set<Resource> res2 = new HashSet<Resource>(a2.getResource());
					LinkedList<Activity> listActInCase = new LinkedList<Activity>();
					
					for (Entry<Case, LinkedList<Activity>> c : hmapCaseActs.entrySet()) {
						if (c.getKey().equals(activityCase)) {
							listActInCase = c.getValue();
						}
					}
					
					boolean clashAgain = true;
					
					while (clashAgain) {
						LinkedList<Activity> listClashingActsAfterShift = 
								new LinkedList<Activity>(newLog.getClashingActivitiesWithin(a2, newStartTime, newLog.getActivityDuration(a2) + newStartTime + timeDifference, res2));
						
						if (listClashingActsAfterShift.size() == 0) {
							newLog.setActivityStart(a2, newStartTime);
							clashAgain = false;
						} else {
							newStartTime = newLog.getActivityEnd(listClashingActsAfterShift.get(0)); //fix this to detect the absolute last activity end among all the list (for loop)
							timeDifference = newStartTime - originalStartTime;
						}
						
					}
					
					if (!clashAgain) {
						for (Activity actInCase : listActInCase) {
							if (!actInCase.equals(a2)) {
								if (newLog.getActivityStart(actInCase) >= activityStartTime) {
									newLog.setActivityStart(actInCase, newLog.getActivityStart(actInCase) + timeDifference);
								}
							}
							
						}
					}
				}
			}
			//newLog = new ConcreteEventLog(newLog.getAbstractLog());

			//newLog.setBoundStartTime(BST);
			/*
			if (repairCount > 5) {
				System.out.println("give up");
				return newLog;
				//break;
			} else {
				repairCount++;
			}
			//*/
		//}
		///*
		/*System.out.println("repairdone"); + newLog.isLogSafe() + newLog.isLogValid() + "-" + 
				newLog.getLogViolatingActivities().get(0).size()+newLog.getLogViolatingActivities().get(1).size()+
				newLog.getLogViolatingActivities().get(2).size()+newLog.getLogViolatingActivities().get(3).size());
		*/
		//GeneticBinder.
		return newLog;
		//*/
		//return newLog;
	}
	/*
	public long getActivityStart(Activity activity) {
		
		//long a = this.boundStartTime.get(activity);
		//if (this.boundStartTime.get(activity) == null) {
			//System.out.println("problemhere-" + activity.getId() + " = " + this.boundStartTime.containsKey(activity));
		//}
		
		return BST.get(activity);
	}
	
	public long getActivityEnd(Activity activity) {
		return getActivityStart(activity) + getActivityDuration(activity);
	}
	
	public long getActivityDuration(Activity activity) {
		return activity.getDuration();
	}
	
	public void setActivityStart(Activity activity, long time) {
		BST.put(activity, time);
	}
	*/
}
